#ifndef COCKPITHBAR_H
#define COCKPITHBAR_H

#include "CockpitBar.h"

#include <QtCore/QString>
#include <QtGui/QBrush>
#include <QtGui/QPainter>
#include <QtGui/QPen>

namespace CockpitHBarUtils
{
enum class ValueRisingDirection
    {
        Left,
        Right
    };

    enum class TextPosition
    {
        Top,
        Bottom
    };
}

template <typename Float>
class CockpitHBar : public CockpitBar<Float>
{
public:
    CockpitHBar(Float value 
                , typename CockpitBar<Float>::RestrictionPolicy restriction_policy = CockpitBar<Float>::NO_RESTRICTION
                , CockpitHBarUtils::ValueRisingDirection value_rising_direction = CockpitHBarUtils::ValueRisingDirection::Left
                , CockpitHBarUtils::TextPosition text_position = CockpitHBarUtils::TextPosition::Top
                )
        : CockpitBar<Float>(value, restriction_policy)
        , _value_rising_direction(value_rising_direction)
        , _text_position(text_position)
    {}

protected:
    void paintEvent(QPaintEvent * event) override
    {
        CockpitBar<Float>::paintEvent(event);

        QPen black_pen(Qt::black);
        black_pen.setWidth(2);

        QPainter painter(this);

        const int ceiled_value = std::ceil(this->value());
        const Float value_shift_right = std::abs(this->value() - ceiled_value);
        const int pixels_shift_right = std::round(value_shift_right * _PIXELS_BETWEEN_LINES);
        
        const Float left_side_x = this->width() * _SIDE_PADDING_MULTIPLIER;
        const Float right_side_x = this->width() - left_side_x;

        const Float central_line_x = this->width() / 2.0 + (_value_rising_direction == CockpitHBarUtils::ValueRisingDirection::Left ? -1.0 : 1.0) * pixels_shift_right;

        {
            const Float centre_x = this->width() / 2.0;
            const Float centre_y = this->height() / 2.0;

            const Float line_side_y = (_text_position == CockpitHBarUtils::TextPosition::Top ? this->height() : 0);
            
            black_pen.setWidth(2);
            painter.setPen(black_pen);

            painter.drawLine(QPointF{centre_x, centre_y}
                            , QPointF{centre_x - _PIXELS_BETWEEN_LINES, line_side_y}
                            );
            painter.drawLine(QPointF{centre_x, centre_y}
                            , QPointF{centre_x + _PIXELS_BETWEEN_LINES, line_side_y}
                            );
        }

        int left_int_value = ceiled_value;
        for (Float left_x = central_line_x; left_side_x <= left_x; left_x -= _PIXELS_BETWEEN_LINES)
        {
            this->drawLine(painter, black_pen, left_x, left_int_value);

            if (_value_rising_direction == CockpitHBarUtils::ValueRisingDirection::Left)
            {
                ++left_int_value;
            } else {
                --left_int_value;
            }
            
            left_int_value = this->restrictionPolicy()(left_int_value);
        }

        int right_int_value = ceiled_value;
        for (Float right_x = central_line_x; right_x <= right_side_x; right_x += _PIXELS_BETWEEN_LINES)
        {
            this->drawLine(painter, black_pen, right_x, right_int_value);

            if (_value_rising_direction == CockpitHBarUtils::ValueRisingDirection::Right)
            {
                ++right_int_value;
            } else {
                --right_int_value;
            }

            right_int_value = this->restrictionPolicy()(right_int_value);
        }
    }

private:
    static constexpr uint _PIXELS_BETWEEN_LINES = 20;
    static constexpr Float _SIDE_PADDING_MULTIPLIER = 1.0 / 20;
    static constexpr Float _LINE_LENGTH_PADDING_MULTIPLIER = 1.0 / 10;
    static constexpr Float _LONG_LINE_LENGTH_PADDING_MULTIPLIER = 1.0 / 20;

    static constexpr uint _TEXT_PEN_WIDTH = 2;
    static constexpr uint _LINE_WIDTH = 2;
    static constexpr uint _BOLD_LINE_WIDTH = 3;
    static constexpr uint _LONG_LINE_WIDTH = 3;

    static constexpr uint _TEXT_SIZE_UNITS = 10;
    static const QString _TEXT_FONT_FAMILY;

    CockpitHBarUtils::ValueRisingDirection _value_rising_direction;
    CockpitHBarUtils::TextPosition _text_position;

    void drawNumber(QPainter & painter, QPen & default_pen, Float x, int number)
    {
        const Float text_y_shift = (this->_text_position == CockpitHBarUtils::TextPosition::Top ? 0 : this->height() / 2.0);
        const Float text_area_width = this->width();
        const Float text_area_height = this->height() / 2.0;

        default_pen.setWidth(_TEXT_PEN_WIDTH);
        painter.setPen(default_pen);
        painter.setFont(CockpitBarUtils::fitTextToRect(QString::number(number)
                                                        , QFont(_TEXT_FONT_FAMILY)
                                                        , {0, 0, _PIXELS_BETWEEN_LINES * _TEXT_SIZE_UNITS, int(text_area_height)}
                                                        )
                        );
        painter.drawText(
            QRectF{x - text_area_width / 2, text_y_shift, text_area_width, text_area_height}
            , Qt::AlignCenter
            , QString::number(number)
            );
    }

    void drawLine(QPainter & painter, QPen & default_pen, Float x, int int_value)
    {
        const Float line_y_shift = (this->_text_position == CockpitHBarUtils::TextPosition::Bottom ? 0 : this->height() / 2.0);

        const Float line_top_y = line_y_shift + this->height() * _LINE_LENGTH_PADDING_MULTIPLIER;
        const Float line_bottom_y = this->height() / 2.0 + line_y_shift - this->height() * _LINE_LENGTH_PADDING_MULTIPLIER;

        const Float long_line_top_y = line_y_shift + this->height() * _LONG_LINE_LENGTH_PADDING_MULTIPLIER;
        const Float long_line_bottom_y = this->height() / 2.0 + line_y_shift - this->height() * _LONG_LINE_LENGTH_PADDING_MULTIPLIER;

        if (std::abs(int_value % 10) == 0)
        {
            this->drawNumber(painter, default_pen, x, int_value);
            default_pen.setWidth(_LONG_LINE_WIDTH);
            painter.setPen(default_pen);
            painter.drawLine(x, long_line_top_y, x, long_line_bottom_y);
        } else if (std::abs(int_value % 5) == 0)
        {
            default_pen.setWidth(_BOLD_LINE_WIDTH);
            painter.setPen(default_pen);
            painter.drawLine(x, line_top_y, x, line_bottom_y);
        } else {
            default_pen.setWidth(_LINE_WIDTH);
            painter.setPen(default_pen);
            painter.drawLine(x, line_top_y, x, line_bottom_y);
        }
    }
};

template <typename Float>
const QString CockpitHBar<Float>::_TEXT_FONT_FAMILY = "monospace";

#endif // COCKPITHBAR_H
